package com.zhl.framework.core.server;

import com.alibaba.fastjson.JSON;
import com.zhl.framework.core.common.RpcInvocation;
import com.zhl.framework.core.common.RpcProtocol;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.EventExecutorGroup;

import java.lang.reflect.Method;

import static com.zhl.framework.core.common.cache.CommonServerCache.PROVIDER_CLASS_MAP;


/**
 * @Author: ZhangLu In DLUT
 * @since: 1.0.0
 * @Description:
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 客户端发送数据过来，进入这个 handler 中就会触发 read 事件
     * @param ctx 封装的通道上下文对象，
     * @param msg 经过解码后的对象，
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        /**
         * 将解码器处理完的数据 rpcProtocol 获取出来
         */
        RpcProtocol rpcProtocol = (RpcProtocol) msg;

        /**
         * 将要进行反序列化操作，将协议对象转换成实际的业务处理对象
         */
        String json = new String(rpcProtocol.getContent(), 0, rpcProtocol.getContentLength());

        /**
         * 这里采用的是最简单的 JSON 序列化方式，可以进行自定义扩展 TODO 优化的点
         */
        RpcInvocation rpcInvocation = JSON.parseObject(json, RpcInvocation.class);
        /**
         * 执行方法的调用
         */
        // 从服务提供者的缓存中获取方法
        Object aimObject  = PROVIDER_CLASS_MAP.get(rpcInvocation.getTargetServiceName());
        Method[] methods = aimObject.getClass().getDeclaredMethods();
        // 遍历所有的方法，找到需要执行的方法
        // 方法返回的结果保存
        Object result = null;
        for (Method method : methods) {
            if (method.getName().equals(rpcInvocation.getTargetMethod())) {
                // 判断是否需要返回值
                if (method.getReturnType().equals(Void.TYPE)) {
                    method.invoke(aimObject, rpcInvocation.getArgs());
                }else {
                    result = method.invoke(aimObject, rpcInvocation.getArgs());
                }
                break;
            }
        }
        // 将返回结果写回传输对象当中
        rpcInvocation.setResponse(result);
        // 结果返回客户端，服务端出站处理
        RpcProtocol respSpcProtocol = new RpcProtocol(JSON.toJSONBytes(rpcInvocation));
        ctx.writeAndFlush(respSpcProtocol);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 打印异常
        cause.printStackTrace();
        // 关闭通道，通道出现了异常
        Channel channel = ctx.channel();
        if (channel.isActive()) {
            channel.close();
        }
    }
}
